package Narzedzia;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import PodsumowaniaLingwistyczne.IKwalifikatorTypu2;
import PodsumowaniaLingwistyczne.ISumaryzatorTypu2;
import PodsumowaniaLingwistyczne.KwalifikatorZlozonyTypu2AND;
import PodsumowaniaLingwistyczne.KwalifikatorZlozonyTypu2OR;
import PodsumowaniaLingwistyczne.SumaryzatorZlozonyTypu2AND;
import PodsumowaniaLingwistyczne.SumaryzatorZlozonyTypu2OR;

public class KazdyZKazdym {

	public static List<ISumaryzatorTypu2> sumaryzatory(List<ISumaryzatorTypu2> sumaryzatory) {

		ArrayList<Wezel> wezly = new ArrayList<Wezel>();
		for (ISumaryzatorTypu2 sumaryzator : sumaryzatory) {
			wezly.add(new Wezel(sumaryzator));
		}

		wygenerujWezly(wezly);
		
		ArrayList<ISumaryzatorTypu2> wygenerowaneSumaryzatoryZlozone = new ArrayList<ISumaryzatorTypu2>();
		wygenerowaneSumaryzatoryZlozone.addAll(sumaryzatory);
		
		for(int poziom = 2; poziom <= sumaryzatory.size(); poziom++){
			List<Wezel> liscieNaPoziomie = znajdzLiscieWszystkichDrzewNaPoziomie(wezly, poziom);
			utworzSumaryzatoryZLisci(liscieNaPoziomie, wygenerowaneSumaryzatoryZlozone);
		}
		
		return wygenerowaneSumaryzatoryZlozone;
	}
	
	private static void utworzSumaryzatoryZLisci(List<Wezel> liscie, ArrayList<ISumaryzatorTypu2> listaNaSumaryzatoryZlozone){
		for(Wezel lisc : liscie){
			listaNaSumaryzatoryZlozone.add(budujSumaryzatorZlozony(lisc));
		}
	}
	
	private static ISumaryzatorTypu2 budujSumaryzatorZlozony(Wezel wezel){
		if(wezel.getOjciec() == null){
			return (ISumaryzatorTypu2) wezel.getBagaz();
		}
		ISumaryzatorTypu2 sumaryzator;
		if(wezel.getCzyAND()){
			sumaryzator = new SumaryzatorZlozonyTypu2AND((ISumaryzatorTypu2)wezel.getBagaz(), budujSumaryzatorZlozony(wezel.getOjciec()));
		}else{
			sumaryzator = new SumaryzatorZlozonyTypu2OR((ISumaryzatorTypu2)wezel.getBagaz(), budujSumaryzatorZlozony(wezel.getOjciec()));
		}
		return sumaryzator;
	}
	
	public static List<IKwalifikatorTypu2> kwalifikatory(List<IKwalifikatorTypu2> kwalifikatory) {

		ArrayList<Wezel> wezly = new ArrayList<Wezel>();
		for (IKwalifikatorTypu2 kwalifikator : kwalifikatory) {
			wezly.add(new Wezel(kwalifikator));
		}

		wygenerujWezly(wezly);
		
		ArrayList<IKwalifikatorTypu2> wygenerowaneKwalifikatoryZlozone = new ArrayList<IKwalifikatorTypu2>();
		wygenerowaneKwalifikatoryZlozone.addAll(kwalifikatory);
		
		for(int poziom = 2; poziom <= kwalifikatory.size(); poziom++){
			List<Wezel> liscieNaPoziomie = znajdzLiscieWszystkichDrzewNaPoziomie(wezly, poziom);
			utworzKwalifikatoryZLisci(liscieNaPoziomie, wygenerowaneKwalifikatoryZlozone);
		}
		
		return wygenerowaneKwalifikatoryZlozone;
	}
	
	private static void utworzKwalifikatoryZLisci(List<Wezel> liscie, ArrayList<IKwalifikatorTypu2> listaNaKwalifikatoryZlozone){
		for(Wezel lisc : liscie){
			listaNaKwalifikatoryZlozone.add(budujKwalifikatorZlozony(lisc));
		}
	}
	
	private static IKwalifikatorTypu2 budujKwalifikatorZlozony(Wezel wezel){
		if(wezel.getOjciec() == null){
			return (IKwalifikatorTypu2) wezel.getBagaz();
		}
		IKwalifikatorTypu2 kwalifikator;
		if(wezel.getCzyAND()){
			kwalifikator = new KwalifikatorZlozonyTypu2AND((IKwalifikatorTypu2)wezel.getBagaz(), budujKwalifikatorZlozony(wezel.getOjciec()));
		}else{
			kwalifikator = new KwalifikatorZlozonyTypu2OR((IKwalifikatorTypu2)wezel.getBagaz(), budujKwalifikatorZlozony(wezel.getOjciec()));
		}
		return kwalifikator;
	}

	private static List<Wezel> znajdzLiscieWszystkichDrzewNaPoziomie(ArrayList<Wezel> korzenie, int poziom) {
		List<Wezel> liscieNaPoziomie = new LinkedList<Wezel>();
		for (Wezel korzen : korzenie) {
			dodajLiscieNaPoziomie(korzen, poziom, liscieNaPoziomie);
		}
		return liscieNaPoziomie;
	}

	private static void dodajLiscieNaPoziomie(Wezel wezel, int poziom, List<Wezel> liscieNaPoziomie) {
		if(wezel.getPoziom() == poziom - 1){
			liscieNaPoziomie.addAll(wezel.getWezly());
			return;
		}
		
		for(Wezel dziecko : wezel.getWezly()){
			dodajLiscieNaPoziomie(dziecko, poziom, liscieNaPoziomie);
		}
	}

	private static void wygenerujWezly(ArrayList<Wezel> wezly) {
		int poziomRoot = 1;
		for (Wezel wezel : wezly) {
			ArrayList<Wezel> wezlyOproczBiezacego = new ArrayList<Wezel>(wezly);
			wezlyOproczBiezacego.remove(wezel);
			wezel.setPoziom(poziomRoot);
			dodajWezly(wezel, poziomRoot, wezlyOproczBiezacego);
		}
	}

	private static void dodajWezly(Wezel root, int poziom, ArrayList<Wezel> wezly) {
		for (Wezel wezel : wezly) {

			ArrayList<Wezel> wezlyOproczBiezacego;
			Wezel nowyWezel = new Wezel(wezel);
			nowyWezel.setCzyAND(true);
			root.getWezly().add(nowyWezel);
			nowyWezel.setOjciec(root);
			nowyWezel.setPoziom(poziom + 1);
			if (wezly.size() > 0) {
				wezlyOproczBiezacego = skopiujWezlyOproczWskazanego(wezly, wezel);
				dodajWezly(nowyWezel, poziom + 1, wezlyOproczBiezacego);
			}

			nowyWezel = new Wezel(wezel);
			nowyWezel.setCzyAND(false);
			root.getWezly().add(nowyWezel);
			nowyWezel.setOjciec(root);
			nowyWezel.setPoziom(poziom + 1);
			if (wezly.size() > 0) {
				wezlyOproczBiezacego = skopiujWezlyOproczWskazanego(wezly, wezel);
				dodajWezly(nowyWezel, poziom + 1, wezlyOproczBiezacego);
			}
		}
	}

	private static ArrayList<Wezel> skopiujWezlyOproczWskazanego(ArrayList<Wezel> wezly, Wezel wskazanyWezel) {
		ArrayList<Wezel> noweWezly = new ArrayList<Wezel>();
		for (Wezel wezel : wezly) {
			if (wezel != wskazanyWezel) {
				noweWezly.add(new Wezel(wezel));
			}
		}
		return noweWezly;
	}

}